package qq2564874169.tuaotuao.fx.log;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.JsonLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class FxLog {
    public static boolean singleFile;
    public static boolean useJsonLayout;
    public static String logDir = "logs";
    public static String msgLayout = "%d{yyyy.MM.dd HH:mm:ss.SSS}  %level\t-%T\t[%c{1.}.%M:%L] - %msg%n%xEx";
    public static final List<String> allow = new ArrayList<>();
    private static LoggerContext logCxt;

    static {
        logCxt = new LoggerContext(FxLog.class.getName());
        logCxt.start();
    }

    private static boolean isAllow(String name) {
        if (allow.isEmpty()) {
            return true;
        }
        for (String item : allow) {
            String regex = item.replace(".", "\\.").replace("*", ".*");
            Pattern pat = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
            if (pat.matcher(name).find()) {
                return true;
            }
        }
        return false;
    }

    private static void set(String name) {
        if (!isAllow(name)) {
            return;
        }
        Configuration config = logCxt.getConfiguration();
        if (config.getLoggers().containsKey(name)) {
            return;
        }
        Level[] defLv = new Level[]{Level.ERROR, Level.WARN, Level.INFO};
        LoggerConfig conf = LoggerConfig.createLogger(false, Level.ALL, name, "true", new AppenderRef[0], null, config, null);
        Layout<?> layout;
        if (useJsonLayout) {
            layout = JsonLayout.newBuilder().setConfiguration(config)
                    .setCompact(true).setLocationInfo(true).setComplete(false).setEventEol(true)
                    .build();
        } else {
            layout = PatternLayout.newBuilder().withConfiguration(config).withPattern(msgLayout).build();
        }
        TimeBasedTriggeringPolicy tp = TimeBasedTriggeringPolicy.newBuilder().withInterval(1).build();
        TriggeringPolicy policy = SizeBasedTriggeringPolicy.createPolicy("10M");
        CompositeTriggeringPolicy composite = CompositeTriggeringPolicy.createPolicy(tp, policy);
        String path = logDir + File.separator;
        if (singleFile == false) {
            path += name.replace(".", File.separator) + File.separator;
        }
        RollingFileAppender fileAppender = RollingFileAppender.newBuilder()
                .setConfiguration(config)
                .setName(name + "_file")
                .setLayout(layout)
                .withFileName(path + "logging.log")
                .withFilePattern(path + "%d{yyyy-MM-dd}.%i.log")
                .withAppend(true)
                .withPolicy(composite)
                .build();
        fileAppender.addFilter(new FxLogFilter(defLv));
        fileAppender.start();

        ConsoleAppender consoleAppender = ConsoleAppender.newBuilder()
                .setConfiguration(config)
                .setName(name + "_console")
                .setLayout(layout)
                .build();
        consoleAppender.addFilter(new FxLogFilter(defLv));
        consoleAppender.start();

        conf.addAppender(fileAppender, null, null);
        conf.addAppender(consoleAppender, null, null);

        config.addLogger(name, conf);
        logCxt.updateLoggers(config);
    }

    public static FxLogFilter getConsoleFilter(String name) {
        Configuration config = logCxt.getConfiguration();
        if (!config.getLoggers().containsKey(name)) {
            return null;
        }
        LoggerConfig conf = config.getLoggerConfig(name);
        Map<String, Appender> map = conf.getAppenders();
        Appender appender = map.get(name + "_console");
        if (appender != null) {
            return (FxLogFilter) ((ConsoleAppender) appender).getFilter();
        }
        return null;
    }

    public static FxLogFilter getFileFilter(String name) {
        Configuration config = logCxt.getConfiguration();
        if (!config.getLoggers().containsKey(name)) {
            return null;
        }
        LoggerConfig conf = config.getLoggerConfig(name);
        Map<String, Appender> map = conf.getAppenders();
        Appender appender = map.get(name + "_file");
        if (appender != null) {
            return (FxLogFilter) ((RollingFileAppender) appender).getFilter();
        }
        return null;
    }

    public static Logger getLogger(Class<?> clazz) {
        if (!logCxt.hasLogger(clazz.getName())) {
            set(clazz.getName());
        }
        return logCxt.getLogger(clazz.getName());
    }
}
